Releases: KilimcininKorOglu/M365Bridge
Releases · KilimcininKorOglu/M365Bridge
Release list
v1.4.9
Changed
- Keep every technical term in its original form in the Turkish documentation and in the Turkish interface catalog.
README.tr.mdtranslated terms the same document keeps in English elsewhere, so one term appeared under two names, andweb/src/locales/tr.jsonshowed the gate screen and the auth notice asAPI anahtarıwhile the same catalog keptgateway,cookieandtranscript - Rename the two
README.tr.mdheadings that a link points at, so neither starts withİ. That letter lowercases toiplus the combining mark U+0307, which an anchor written with a plaininever reaches
Fixed
- Correct two
README.tr.mdsentences that stated the wrong fact: theM365_CLIENT_IDrow 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
Added
- Route a Codex
compaction_triggeritem in a/v1/responsesinput 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.mdandREADME.tr.mdaround one setup chapter
Fixed
- Print the same browser snippet in the setup wizard that both READMEs document
v1.4.7
Fixed
- Start a conversation in the browser interface when the gateway is reached over plain
httpon a LAN address.crypto.randomUUIDcarries[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 onlocalhost, which is why the failure only appeared on a deployment. The session id now comes fromgetRandomValues, the one member ofCryptoan insecure context still offers, and falls back to a timestamp only where neither exists
v1.4.6
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 sameAuthorizationheader 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/authwith the gate the browser interface must show (none,passwordorapi_key), andPOST /v1/auth/verifywith 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_PASSWORDandM365_API_KEYSare 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
Added
- Translate the browser interface from JSON catalogs. Every file under
web/src/localesis a language, so a fork adds one by dropping a file there and runningmake ui. The choice is stored in them365bridge_langcookie, 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-Idfrom Claude Code andSession-Idfrom Codex, both below any session the caller names explicitly - Accept
stopon/v1/chat/completionsand/v1/completions, andstop_sequenceson/v1/messagesand/v1/complete, on both the streaming and the non-streaming paths - Report the stop sequence that ended a completion, as
nullrather than an empty string when the answer ended on its own - Honour
parallel_tool_calls: falseanddisable_parallel_tool_useby 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_aton every Responses lifecycle event - Read a bare url under an
image_urlorinput_imageblock, which is the form several clients send - Carry a
developermessage as instructions, the role OpenAI's reasoning models use in place ofsystem - Honour a
json_schemaresponse 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/messagesand/v1/completereadsession_idanduserfrom 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
Added
- Keep a Responses turn inside an unfinished Codex goal as
commentaryrather thanfinal_answer, so the client continues the turn until anupdate_goaloutput reportscompleteorblocked
Fixed
- Stream a custom tool's input over
response.custom_tool_call_input.deltaand.doneinstead ofresponse.function_call_arguments, and name it by the item id the surroundingoutput_itemevents announced - Carry an
input_imageblock through the Responses input converter; the image was flattened away before the upload step the path already had - Read a Responses
input_imageurl as the bare string the API sends, and accept theinput_textandoutput_textblock names
Changed
- Keep the
customdeclaration 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
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
LoadConfigapplies, 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_KEYandTZas environment variables in both READMEs; the two the process exits without were absent - State in
--helpand in both READMEs that every flag is optional, and which defaultsserveandsetup-wizardapply when none is given - List
--helpitself in the usage text
v1.4.2
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
Added
- Serve a browser interface at
/from files embedded in the binary, gated onM365_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/transcriptsand read them back overGET /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
ReadHeaderTimeoutandIdleTimeouton 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
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/modelsroute - 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
maxreasoning effort and describe every preset - Expose the session to conversation mapping over
/v1/sessionsand/v1/sessions/{id} - Store the session id and a timestamp in the context cache
- Add the
/v1/healthreachability 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_choicewhen 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_searchto the client - Keep tool call structure after text flattening
- Accept the Responses reasoning block and emit custom tools as
custom_tool_callin 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
typeand the machine-readable string incode - Drop a streaming turn when its client disconnects, and bound SSE writes to a gone client
- Count tokens with
o200k_baseand 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-keyas well asAuthorization - Include the
signaturefield on Anthropic thinking blocks - Serialize refresh token redemption
- Preserve tool schemas and namespaces