Skip to content

Releases: KilimcininKorOglu/M365Bridge

v1.4.9

Choose a tag to compare

@github-actions github-actions released this 24 Aug 18:07

Changed

  • Keep every technical term in its original form in the Turkish documentation and in the Turkish interface catalog. README.tr.md translated terms the same document keeps in English elsewhere, so one term appeared under two names, and web/src/locales/tr.json showed the gate screen and the auth notice as API anahtarı while the same catalog kept gateway, cookie and transcript
  • Rename the two README.tr.md headings that a link points at, so neither starts with İ. That letter lowercases to i plus the combining mark U+0307, which an anchor written with a plain i never reaches

Fixed

  • Correct two README.tr.md sentences that stated the wrong fact: the M365_CLIENT_ID row said the access tokens are arranged rather than issued to the client, and the broker refresh token step read as "returned by the refresher" where the token is rotated by it

v1.4.8

Choose a tag to compare

@github-actions github-actions released this 24 Aug 17:40

Added

  • Route a Codex compaction_trigger item in a /v1/responses input to /v1/responses/compact. Codex sends that item when it wants a conversation compacted; without the routing the request was answered as an ordinary turn, which consumed a message from the conversation quota and returned an answer instead of a summary. The item is also skipped during message conversion, so a stray trigger never reaches the prompt

Changed

  • Rewrite README.md and README.tr.md around one setup chapter

Fixed

  • Print the same browser snippet in the setup wizard that both READMEs document

v1.4.7

Choose a tag to compare

@github-actions github-actions released this 24 Aug 15:59

Fixed

  • Start a conversation in the browser interface when the gateway is reached over plain http on a LAN address. crypto.randomUUID carries [SecureContext] in the Web Cryptography IDL, so a browser outside a trusted origin does not carry it and naming a new session threw. The interface worked behind TLS and on localhost, which is why the failure only appeared on a deployment. The session id now comes from getRandomValues, the one member of Crypto an insecure context still offers, and falls back to a timestamp only where neither exists

v1.4.6

Choose a tag to compare

@github-actions github-actions released this 23 Aug 11:35

Added

  • Gate the browser interface with M365_WEB_UI_PASSWORD. An unset value leaves the interface open, as before. The password is one more credential the gateway accepts rather than a session of its own: the browser holds it in a cookie and sends it in the same Authorization header an API client sends its key in, so every credential stays on a header where a cross-site form cannot carry it
  • Answer GET /v1/auth with the gate the browser interface must show (none, password or api_key), and POST /v1/auth/verify with whether an offered credential is accepted. Both are public, because the page that asks for a credential is served without one and cannot otherwise learn what to ask for. Without the verify route a wrong password would look like a right one whenever no API key is configured, since every route answers 200 then

Changed

  • M365_WEB_UI_PASSWORD and M365_API_KEYS are separate switches. A password with no key gates the interface and leaves the API open, which is what an empty key list means everywhere else in this gateway

Fixed

  • Compare every secret in constant time. The API key check returned as soon as two bytes differed, which let a caller measure how much of a guess was right

v1.4.5

Choose a tag to compare

@github-actions github-actions released this 23 Aug 11:02

Added

  • Translate the browser interface from JSON catalogs. Every file under web/src/locales is a language, so a fork adds one by dropping a file there and running make ui. The choice is stored in the m365bridge_lang cookie, English is the default, and a language the build does not carry resolves to English and rewrites the cookie
  • Render an answer and its reasoning block as markdown, so a comparison table is a table and a citation is a link rather than a bare URL in the middle of a sentence. A user message stays literal
  • Give every conversation its own address, /c/{session id}, so it can be reloaded onto, linked to, and reached with the browser's back and forward buttons
  • Ask for a rename or a delete inside the page instead of through the browser's own dialogs
  • Read the session id an agent client stamps on its request: X-Claude-Code-Session-Id from Claude Code and Session-Id from Codex, both below any session the caller names explicitly
  • Accept stop on /v1/chat/completions and /v1/completions, and stop_sequences on /v1/messages and /v1/complete, on both the streaming and the non-streaming paths
  • Report the stop sequence that ended a completion, as null rather than an empty string when the answer ended on its own
  • Honour parallel_tool_calls: false and disable_parallel_tool_use by returning a single tool call

Fixed

  • Store a session's conversation before writing the end of a response, never after. A client that read the terminator and asked about its session at once was told the session does not exist, which made the browser interface show one conversation as two rows
  • Delete a conversation on both sides whichever side starts, and clear every session bound to it, because more than one session can point at one conversation
  • Keep each column's scrollbar inside its own column in the browser interface; a long conversation used to scroll the whole page and the sidebar list never scrolled on its own
  • Report created_at on every Responses lifecycle event
  • Read a bare url under an image_url or input_image block, which is the form several clients send
  • Carry a developer message as instructions, the role OpenAI's reasoning models use in place of system
  • Honour a json_schema response format
  • End a completion at its stop sequence, including a sequence split across two upstream chunks
  • Stop reading an answer that discusses sandboxes as a refusal
  • Bound the request body every handler reads and every upstream response body this proxy reads
  • Replace every state file in one step instead of truncating it, so a failed write cannot leave a half-written credential store
  • Cut text on a rune boundary wherever a byte cap applies
  • Report a response body that failed to encode instead of sending a truncated one

Changed

  • Resolve every request's session through one order, so /v1/completions, /v1/messages and /v1/complete read session_id and user from the body like the other endpoints
  • Cut text on a character boundary from one place rather than at each call site
  • Drop the unused scoped token exchange from the authentication layer
  • Remove the dependabot configuration
  • Rewrite both READMEs against the running service: the Go floor, the package list, the Anthropic SDK base URL, the capability tree shape, the MCP tool arguments, the image backend name, 413 request_too_large, and what an unserved model name returns

v1.4.4

Choose a tag to compare

@github-actions github-actions released this 20 Aug 19:29

Added

  • Keep a Responses turn inside an unfinished Codex goal as commentary rather than final_answer, so the client continues the turn until an update_goal output reports complete or blocked

Fixed

  • Stream a custom tool's input over response.custom_tool_call_input.delta and .done instead of response.function_call_arguments, and name it by the item id the surrounding output_item events announced
  • Carry an input_image block through the Responses input converter; the image was flattened away before the upload step the path already had
  • Read a Responses input_image url as the bare string the API sends, and accept the input_text and output_text block names

Changed

  • Keep the custom declaration when one tool name is declared both freeform and as a function, because a freeform body is not the JSON a client parses in function-call arguments

v1.4.3

Choose a tag to compare

@github-actions github-actions released this 20 Aug 18:37

Changed

  • Print every environment variable the binary reads in --help, grouped by what it affects, instead of naming four and deferring the rest to the README
  • Read the documented defaults from the same constants LoadConfig applies, so a changed default cannot leave a stale value in the usage text
  • Document M365_TENANT_ID, M365_USER_OID, M365_CLIENT_ID, M365_API_KEYS, M365_API_KEY and TZ as environment variables in both READMEs; the two the process exits without were absent
  • State in --help and in both READMEs that every flag is optional, and which defaults serve and setup-wizard apply when none is given
  • List --help itself in the usage text

v1.4.2

Choose a tag to compare

@github-actions github-actions released this 20 Aug 18:01

Fixed

  • Keep the conversation a built-in coding tool loop created when the loop ends on an error, instead of orphaning it and starting a new one on the next turn
  • Compare coding tool calls by signature rather than by raw arguments, so a repeat that differs only in JSON key order or whitespace no longer runs the tool again

v1.4.1

Choose a tag to compare

@github-actions github-actions released this 20 Aug 17:34

Added

  • Serve a browser interface at / from files embedded in the binary, gated on M365_ENABLE_WEB_UI
  • Add the chat interface with a conversation sidebar, streaming answers and model selection
  • Keep the composer in place while the conversation scrolls and move the model picker into it
  • Record the turns of a session under data/transcripts and read them back over GET /v1/sessions/{id}/messages
  • Bind a session to a conversation that already exists with PUT /v1/sessions/{id}
  • Read a conversation this gateway never carried from the M365 conversation page
  • Import an upstream conversation into a session over GET /v1/conversations/{id}/messages
  • Offer to load the history of a conversation started in the M365 web or mobile client
  • Document the whole command surface in --help, including both subcommands and the environment variables

Changed

  • Set ReadHeaderTimeout and IdleTimeout on the HTTP server, and tighten the log file, the written coding-tool file and their directories to owner-only
  • State on every remaining static-analysis finding why the code is safe, so a real one cannot hide in the noise
  • Cover the coding-tool workspace escape and the written file mode with tests
  • Describe the web interface and reading a conversation held upstream in both READMEs
  • Ignore the Go build cache directory

Fixed

  • Strip the backend's raw citation markers from answer text on every channel
  • Check the error every discarded call returns, and report a failed cache directory instead of proceeding without one
  • Restrict a log file an earlier build left readable

v1.4.0

Choose a tag to compare

@github-actions github-actions released this 20 Aug 12:58

Added

  • Expose Copilot through a JSON-RPC 2.0 Model Context Protocol server on /mcp
  • Publish the OpenAI and the Anthropic model schema from a single /v1/models route
  • Advertise the Codex catalog fields, owner, input budget and tool support in the model list
  • Publish three measured tones and state thinking support per model entry
  • Accept max reasoning effort and describe every preset
  • Expose the session to conversation mapping over /v1/sessions and /v1/sessions/{id}
  • Store the session id and a timestamp in the context cache
  • Add the /v1/health reachability probe
  • Surface the M365 conversation quota and report throttling
  • Add context window configuration and defaults
  • Report usage on the Anthropic Complete endpoint and on the streaming completions route
  • Commit stream headers before the upstream turn and keep every SSE stream alive during upstream silence
  • Carry the upstream HTTP status out of failed requests
  • Report an M365 content refusal as a distinct error
  • Add the evidence ledger for client-driven tool loops, and cap the tool rounds one turn may drive
  • Put settled tool results into the simulation prompt and stop forwarding a tool call whose result is already settled
  • Replace a completion report that no tool result backs
  • Accept a progress note for a running client tool
  • Validate tool call arguments against their JSON schema and enforce tool_choice when parsing the model response
  • Reject tool results that answer no declared tool call
  • Re-ask when the backend answers a tool request with prose, and claim an unfenced grammar tool body as a call
  • Widen the sandbox refusal detector to more phrasings
  • Stop routing a declared web_search to the client
  • Keep tool call structure after text flattening
  • Accept the Responses reasoning block and emit custom tools as custom_tool_call in Responses output
  • Fetch caller-supplied remote image URLs
  • Log file and audio content blocks instead of dropping them silently

Changed

  • Answer an empty Responses probe without an upstream turn
  • Accumulate streamed text with strings.Builder
  • Drop values no caller reads
  • Restrict generated-image downloads to allowed hosts
  • Document the error contract, the tool contract, the session routes, usage reporting, SSE resilience and the setup that does not use Docker

Fixed

  • Never forward M365's own tool calls, and keep the backend's own tool messages out of the answer
  • Stop a re-encoded snapshot from repeating the answer
  • Report a turn the backend ended without an answer, and a turn that ends with no answer and no verdict
  • Reject a model this service does not serve instead of folding it into the auto entry
  • Serve the reasoning model from a tone that reasons
  • Print the CLI model list in a stable order
  • Classify upstream failures instead of reporting them all as 500
  • Put the error category in type and the machine-readable string in code
  • Drop a streaming turn when its client disconnects, and bound SSE writes to a gone client
  • Count tokens with o200k_base and report the source
  • Count Anthropic prompt tokens like every other endpoint
  • Report usage from the buffered coding-tool responders
  • Bill tool choice framing only when tools were declared
  • Reject a repeated tool call id and make tool call IDs unique
  • Bound the tool result text the ledger carries
  • Recognize every exit-code wording as a failure
  • Keep backend calls suppressed for a web_search-only request
  • Claim a grammar body wrapped in a valid envelope, and withhold an unparseable transport envelope from the answer
  • Replace the unverified claim on the buffered streams too
  • Match the backend's observed Turkish refusal wording
  • Identify the proxy when fetching a remote image
  • Accept the API key from x-api-key as well as Authorization
  • Include the signature field on Anthropic thinking blocks
  • Serialize refresh token redemption
  • Preserve tool schemas and namespaces